<?php
Yii::import('lib.giiadv.components.TextDiff');
class DbMonitorHelper extends CComponent {
	
	protected $_db;
	protected $_dbmTables;
	protected $_tableInfos;
	
	protected static $_stripTables = array(
		'dbm_table', 'dbm_history',
	);
	
	public static function getInstance() {
		return new self();
	}
	
	public function getDbmTables() {
		return $this->getDb()->tables;
	}
	
	public function getTableInfos() {
		if(!$this->_tableInfos) {
			$this->_tableInfos = DbmTableInfoSchema::model()->findAll();
		}
		return $this->_tableInfos;
	}
	
	/**
	 * 寻找需要处理的表
	 * 返回需要填充的的表名和需要更新的表名
	 * @param array $dbmTables
	 * @return array
	 */
	public function getProcessTables($dbmTables) {
		$db = $this->getDb();
		$tablesInfo = $this->getTableInfos();
		
		$current = CHtml::listData($dbmTables, 'table_name', 'last_update');
		$last = CHtml::listData($tablesInfo, 'TABLE_NAME', 'UPDATE_TIME');
		
		// 先找出更新时间大于当前时间的表
		$needUpdate = array();
		foreach($current as $tableName=>$time) {
			if(array_key_exists($tableName, $last)) {
				$lastTime = $last[$tableName];
				if($lastTime > $time || !$time) {
					$needUpdate[] = $tableName;
				}
				unset($last[$tableName]);
			}
		}
		
		$needFill = array_keys($last);
		
		return array(
			$needFill,
			array_merge($needUpdate, $needFill),
		);
	}
	
	/**
	 * 去除不需要的表名
	 * @param array $strips
	 * @return array
	 */
	public static function stripTables($strips) {
		$tables = array();
		foreach($strips as $table) {
			if(!in_array($table, self::$_stripTables)) {
				$tables[] = $table;
			}
		}
		return $tables;
	}
	
	/**
	 * 查看表结构
	 * @param string $tableName
	 * @return string
	 */
	public function showCreateTable($tableName) {
		$reader = $this->getDb()->createCommand("SHOW CREATE TABLE `{$tableName}`")->queryRow();
		return isset($reader['Create Table']) ? $reader['Create Table'] : '';
	}
	
	/**
	 * 刷新表
	 * @param array $tables
	 * @return boolean
	 */
	public function refresh($tables = null) {
		
		$db = $this->getDb();
		$dbmTables = $db->getTables();
		$tables = (array)$tables;
		if($tables) {
			$needUpdate = $tables;
		} else {
			list($needFill, $needUpdate) = $this->getProcessTables($dbmTables);		
			if($this->fillTables($needFill)) {
				$dbmTables = $db->getTables(true);
			}
		}
		
		foreach($this->stripTables($needUpdate) as $tableName) {
			
			$lastSql = $dbmTables[$tableName]->last_sql;
			$currentSql = $this->showCreateTable($tableName);
			
			list($sql, $diff) = self::diff($lastSql, $currentSql);

			if($diff) {
				$update = new DbmHistory();
				$update->attributes = array(
					'sql' => $sql,
					'table_name' => $tableName,
					'diff_last' => $diff,
				);
				$update->save();
			}
			
		}
		return true;
	}
	
	/**
	 * 填充新表
	 * @param array $tables
	 * @return boolean
	 */
	public function fillTables($tables) {
		$tables = $this->stripTables($tables);
		if(!$tables) return false;
		foreach($tables as &$v) {
			$v = "('{$v}')";
		}
		try {
			$sql = 'INSERT INTO `dbm_table`(`table_name`) VALUES'.implode(',', $tables);
			self::getDb()->createCommand($sql)->execute();
		} catch (Exception $e) {
			return false;
		}
		return true;
	}
	
	/**
	 * 比较差异代码
	 * @param string $last
	 * @param string $current
	 * @return array
	 */
	public function diff($last, $current) {
		if($last == '') {
			$currentLines = explode("\n", $current);
			unset($currentLines[count($currentLines)-1], $currentLines[0]);
			$currentColumns = implode("\n", $currentLines);
			
			return array($current, $currentColumns);
		}
		
		$lastLines = explode("\n", $last);
		$currentLines = explode("\n", $current);
		
		$firstLine = $lastLines[0];
		$lastLine = $lastLines[count($lastLines)-1];
		
		unset($lastLines[count($lastLines)-1], $lastLines[0],
			$currentLines[count($currentLines)-1], $currentLines[0]
		);
		
		$last = implode("\n", $lastLines);
		$current = implode("\n", $currentLines);
		
		$diff = TextDiff::compare($last, $current);
		return array(
			$firstLine."\n".$current."\n".$lastLine,
			$diff ? $diff : '',
		);
	}
	
	public function createTable() {
		
		$sql = "
		DROP TABLE IF EXISTS `dbm_table`;
		CREATE TABLE `dbm_table` (
		  `table_name` varchar(100) NOT NULL COMMENT '表名',
		  `package` varchar(100) DEFAULT 'db' COMMENT '包',
		  `desc` text COMMENT '描述',
		  PRIMARY KEY (`table_name`)
		) ENGINE=MyISAM DEFAULT CHARSET=utf8;
		DROP TABLE IF EXISTS `dbm_history`;
		CREATE TABLE `dbm_history` (
		  `id` int(11) NOT NULL AUTO_INCREMENT,
		  `table_name` varchar(255) DEFAULT NULL COMMENT '表名',
		  `sql` longtext COMMENT 'SQL',
		  `diff_last` longtext COMMENT '上次差异',
		  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
		  `remark` text COMMENT '备注',
		  `author` varchar(30) DEFAULT 'admin' COMMENT '修改人',
		  PRIMARY KEY (`id`)
		) ENGINE=MyISAM DEFAULT CHARSET=utf8
		";

		return self::getDb()->createCommand($sql)->execute();
	}
	
	public function getDb() {
		return DbmDb::getInstance();
	}
	
}
